#include "Overseer.h"
#include "InputManager.h"
#include "GUIManager.h"
#include "Settings.h"
#include "State.h"

template<> Overseer* Ogre::Singleton<Overseer>::msSingleton = 0;

Overseer::Overseer()
    : nextState(0),running(false)
{
}

bool Overseer::initialise()
{
    root = new Ogre::Root();
    if (!root->showConfigDialog()) return false;
    window = root->initialise(true, "Fortress Overseer v0.70");
    Ogre::WindowEventUtilities::addWindowEventListener(window,this);
    running = true;
    setupResources();
    inputManager = new InputManager();
    inputManager->initialise(window);
    guiManager = new GUIManager();
    guiManager->initialise();
    inputManager->addKeyListener(guiManager,"GUIManager");
    inputManager->addMouseListener(guiManager,"GUIManager");
    Settings *settings = new Settings();
    settings->initialise();
    return true;
}

void Overseer::setupResources()
{
    Ogre::ConfigFile cf;
    cf.load("resources.cfg");

    Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();

    Ogre::String secName, typeName, archName;
    while (seci.hasMoreElements())
    {
        secName = seci.peekNextKey();
        Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
        Ogre::ConfigFile::SettingsMultiMap::iterator i;
        for (i = settings->begin(); i != settings->end(); ++i)
        {
            typeName = i->first;
            archName = i->second;
            Ogre::ResourceGroupManager::getSingletonPtr()->addResourceLocation(archName,typeName,secName);
        }
    }
    Ogre::TextureManager::getSingletonPtr()->setDefaultNumMipmaps(5);
}

bool Overseer::isRunning()
{
    return running;
}

void Overseer::update()
{
    Ogre::WindowEventUtilities::messagePump();
    Ogre::Real timeSinceLastFrame = (timer.getMilliseconds()-lastTime)/1000.0f;
    lastTime = (Ogre::Real)timer.getMilliseconds();
    inputManager->capture();
    guiManager->update(timeSinceLastFrame);
    stateMutex.lock();
    if (!states.empty()) states.back()->update(timeSinceLastFrame);
    manageStates();
    stateMutex.unlock();
    root->renderOneFrame();
}

void Overseer::manageStates()
{
    boost::mutex::scoped_lock lock(stateOpMutex);
    switch(stateOp)
    {
    case STATE_NONE:
        break;
    case STATE_CHANGE:
        if (!states.empty())
        {
            states.back()->exit();
            states.pop_back();
        }
        states.push_back(nextState);
        states.back()->initialise();
        inputManager->addKeyListener(nextState,nextState->getName());
        inputManager->addMouseListener(nextState,nextState->getName());
        break;
    case STATE_PUSH:
        if (!states.empty()) states.back()->pause();
        states.push_back(nextState);
        states.back()->initialise();
        inputManager->addKeyListener(nextState,nextState->getName());
        inputManager->addMouseListener(nextState,nextState->getName());
        break;
    case STATE_POP:
        if (!states.empty())
        {
            inputManager->removeKeyListener(states.back()->getName());
            inputManager->removeMouseListener(states.back()->getName());
            states.back()->exit();
            states.pop_back();
        }
        if (!states.empty()) states.back()->resume();
        break;
    default:
        break;
    }
    nextState = 0;
    stateOp = STATE_NONE;
}

void Overseer::changeState(State *s)
{
    boost::mutex::scoped_lock lock(stateOpMutex);
    nextState = s;
    stateOp = STATE_CHANGE;
}

void Overseer::pushState(State *s)
{
    boost::mutex::scoped_lock lock(stateOpMutex);
    nextState = s;
    stateOp = STATE_PUSH;
}

void Overseer::popState()
{
    boost::mutex::scoped_lock lock(stateOpMutex);
    stateOp = STATE_POP;
}

State* Overseer::getCurrentState()
{
    boost::mutex::scoped_lock lock(stateMutex);
    if (!states.empty()) return states.back();
    else return NULL;
}

void Overseer::exit()
{
    running = false;
}

void Overseer::cleanup()
{
    inputManager->removeAllKeyListeners();
    inputManager->removeAllMouseListeners();
    while (!states.empty())
    {
        states.back()->exit();
        states.pop_back();
    }
}

GUIManager* Overseer::getGUIManager()
{
    return guiManager;
}

InputManager* Overseer::getInputManager()
{
    return inputManager;
}

void Overseer::windowClosed(Ogre::RenderWindow *rw)
{
    exit();
}

void Overseer::windowResized(Ogre::RenderWindow *rw)
{
    inputManager->setWindowSize(rw->getWidth(), rw->getHeight());
    guiManager->setWindowSize(rw->getWidth(), rw->getHeight());
}

void Overseer::windowFocusChange(Ogre::RenderWindow *rw)
{
}
